#include "link32fa016bx_sfc.h"

void sfc_deinit()
{
	SFC_CFG &= ~SFC_CFG_SFC_EN_Msk;
}

void sfc_init(sfc_cfg_struct *cfg)
{
	SFC_CFG = SFC_CFG_SFC_EN_Msk | \
		  ((cfg->byte_order << SFC_CFG_BYTE_ORDER_Pos) & SFC_CFG_BYTE_ORDER_Msk) | \
		  ((cfg->spi_pol_pha << SFC_CFG_CPOL_CPHA_Pos) & SFC_CFG_CPOL_CPHA_Msk) | \
		  ((cfg->csn_lead_time << SFC_CFG_CSN_SETUP_TIMES_Pos) & SFC_CFG_CSN_SETUP_TIMES_Msk) | \
		  ((cfg->csn_tail_time << SFC_CFG_CSN_HOLD_TIMES_Pos) & SFC_CFG_CSN_HOLD_TIMES_Msk) | \
		  ((cfg->csn_idle_time << SFC_CFG_SPI_IDLE_TIMES_Pos) & SFC_CFG_SPI_IDLE_TIMES_Msk) | \
		  ((cfg->clk_div << SFC_CFG_SCK_DIV_PRE_Pos) & SFC_CFG_SCK_DIV_PRE_Msk);
}

void sfc_cmd_init(sfc_cmd_struct *cmd)
{
	SFC_CMD = SFC_CMD_CMD_FINAL_Msk | \
		((cmd->cmd << SFC_CMD_FLASH_CMD_Pos) & SFC_CMD_FLASH_CMD_Msk) | \
		(((cmd->dummy_bytes-1) << SFC_CMD_DUMMY_BYTES_Pos) & SFC_CMD_DUMMY_BYTES_Msk) | \
		(((cmd->addr_bytes-1) << SFC_CMD_ADDR_BYTES_Pos) & SFC_CMD_ADDR_BYTES_Msk) | \
		((cmd->data_speed << SFC_CMD_DATA_SPEED_Pos) & SFC_CMD_DATA_SPEED_Msk) | \
		((cmd->dummy_speed << SFC_CMD_DUMMY_SPEED_Pos) & SFC_CMD_DUMMY_SPEED_Msk) | \
		((cmd->addr_speed << SFC_CMD_ADDR_SPEED_Pos) & SFC_CMD_ADDR_SPEED_Msk) | \
		((cmd->cmd_speed << SFC_CMD_CMD_SPEED_Pos) & SFC_CMD_CMD_SPEED_Msk) | \
		((cmd->data_phase << SFC_CMD_DATA_PHASE_Pos) & SFC_CMD_DATA_PHASE_Msk) | \
		((cmd->dummy_phase << SFC_CMD_DUMMY_PHASE_Pos) & SFC_CMD_DUMMY_PHASE_Msk) | \
		((cmd->addr_phase << SFC_CMD_ADDR_PHASE_Pos) & SFC_CMD_ADDR_PHASE_Msk) | \
		((cmd->cmd_phase << SFC_CMD_CMD_PHASE_Pos) & SFC_CMD_CMD_PHASE_Msk) | \
		((cmd->data_dir << SFC_CMD_DATA_DIR_Pos) & SFC_CMD_DATA_DIR_Msk);
}
void sfc_flash_cmd_only()
{
	SFC_CTRL &= ~SFC_CTRL_CMD_TYPE_Msk;
	SFC_CTRL |= SFC_CTRL_CMD_START_Msk;
	while(SFC_STAT & SFC_STAT_CMD_BUSY_Msk);
}

void sfc_flash_erase(uint32_t addr)
{
	SFC_CTRL &= ~SFC_CTRL_CMD_TYPE_Msk;
	SFC_CMD_ADDR = addr;
	SFC_CTRL |= SFC_CTRL_CMD_START_Msk;
	while(SFC_STAT & SFC_STAT_CMD_BUSY_Msk);
}

void sfc_flash_rd_reg(uint8_t *data)
{
	uint32_t byte_order_be;
	SFC_CMD |= SFC_CMD_XTS_BYPASS_Msk;
	SFC_CTRL &= ~SFC_CTRL_FRAME_BITS_Msk;
	SFC_CTRL |= ((7 << SFC_CTRL_FRAME_BITS_Pos) & SFC_CTRL_FRAME_BITS_Msk);
	SFC_CTRL &= ~SFC_CTRL_CMD_TYPE_Msk;
	SFC_CTRL |= SFC_CTRL_RX_FIFO_CLR_Msk;
	SFC_CTRL |= SFC_CTRL_CMD_START_Msk;
	while(SFC_STAT & SFC_STAT_CMD_BUSY_Msk);
	byte_order_be = (SFC_CFG & SFC_CFG_BYTE_ORDER_Msk) >> SFC_CFG_BYTE_ORDER_Pos;
	if(byte_order_be)
		*data = (uint8_t)(SFC_CMD_DATA >> 24);
	else
		*data = (uint8_t)SFC_CMD_DATA;
}

void sfc_flash_wr_reg(uint8_t *data)
{
	uint32_t byte_order_be;
	SFC_CMD |= SFC_CMD_XTS_BYPASS_Msk;
	SFC_CTRL &= ~SFC_CTRL_FRAME_BITS_Msk;
	SFC_CTRL |= ((7 << SFC_CTRL_FRAME_BITS_Pos) & SFC_CTRL_FRAME_BITS_Msk);
	SFC_CTRL &= ~SFC_CTRL_CMD_TYPE_Msk;
	SFC_CTRL |= SFC_CTRL_TX_FIFO_CLR_Msk;
	SFC_CTRL |= SFC_CTRL_CMD_START_Msk;
	byte_order_be = (SFC_CFG & SFC_CFG_BYTE_ORDER_Msk) >> SFC_CFG_BYTE_ORDER_Pos;
	if(byte_order_be)
		SFC_CMD_DATA = (uint32_t)(*data) << 24;
	else
		SFC_CMD_DATA = (uint32_t)(*data);

	while(SFC_STAT & SFC_STAT_CMD_BUSY_Msk);
	return;
}


ErrStatus sfc_flash_pg(uint32_t xts_bypass, uint32_t addr, uint32_t data_bits, uint8_t* data)
{
	int i, idx, num_words, num_bytes;
	uint8_t cur_data;
	uint32_t tmp_data = 0;
	uint32_t byte_order_be;
	if(!xts_bypass && data_bits != 128)
		return ERROR;
	if(data_bits <= 32) {
	       if(data_bits & 0x7)
			return ERROR;
	} else {
		if((data_bits != 64) || (data_bits != 128))
			return ERROR;
	}
	if(xts_bypass) {
		SFC_CMD |= SFC_CMD_XTS_BYPASS_Msk;
	} else {
		SFC_CMD &= ~SFC_CMD_XTS_BYPASS_Msk;
	}
	SFC_CTRL &= ~SFC_CTRL_FRAME_BITS_Msk;
	SFC_CTRL |= (((data_bits-1) << SFC_CTRL_FRAME_BITS_Pos) & SFC_CTRL_FRAME_BITS_Msk);
	SFC_CTRL &= ~SFC_CTRL_CMD_TYPE_Msk;
	byte_order_be = (SFC_CFG & SFC_CFG_BYTE_ORDER_Msk) >> SFC_CFG_BYTE_ORDER_Pos;
	SFC_CMD_ADDR = addr;
	SFC_CTRL |= SFC_CTRL_TX_FIFO_CLR_Msk;
	SFC_CTRL |= SFC_CTRL_CMD_START_Msk;
	num_bytes = data_bits >> 3;
	num_words = (num_bytes >> 2) + ((num_bytes & 0x3) ? 1 : 0);
	idx = 0;
	for(i = 0; i < (num_words<<2); i++) {
		if(idx < num_bytes)
			cur_data = data[idx++];
		else
			cur_data = 0;
		if(byte_order_be)
			tmp_data = (tmp_data << 8) | (uint32_t)cur_data;
		else
			tmp_data = (tmp_data >> 8) | ((uint32_t)cur_data << 24);
		if((i & 0x3) == 0x3)
			SFC_CMD_DATA = tmp_data;
	}
	while(SFC_STAT & SFC_STAT_CMD_BUSY_Msk);
	return SUCCESS;
}

ErrStatus sfc_flash_rd(uint32_t xts_bypass, uint32_t addr, uint32_t data_bits, uint8_t* data)
{
	int i, j, idx, num_words, num_bytes;
	uint32_t tmp_data;
	uint32_t byte_order_be;
	if(!xts_bypass && data_bits != 128)
		return ERROR;
	if(data_bits <= 32) {
	       if(data_bits & 0x7)
			return ERROR;
	} else {
		if((data_bits != 64) || (data_bits != 128))
			return ERROR;
	}

	if(xts_bypass) {
		SFC_CMD |= SFC_CMD_XTS_BYPASS_Msk;
	} else {
		SFC_CMD &= ~SFC_CMD_XTS_BYPASS_Msk;
	}
	SFC_CTRL &= ~SFC_CTRL_FRAME_BITS_Msk;
	SFC_CTRL |= (((data_bits-1) << SFC_CTRL_FRAME_BITS_Pos) & SFC_CTRL_FRAME_BITS_Msk);
	SFC_CTRL &= ~SFC_CTRL_CMD_TYPE_Msk;
	byte_order_be = (SFC_CFG & SFC_CFG_BYTE_ORDER_Msk) >> SFC_CFG_BYTE_ORDER_Pos;
	SFC_CMD_ADDR = addr;
	SFC_CTRL |= SFC_CTRL_RX_FIFO_CLR_Msk;
	SFC_CTRL |= SFC_CTRL_CMD_START_Msk;
	while(SFC_STAT & SFC_STAT_CMD_BUSY_Msk);
	num_bytes = data_bits >> 3;
	num_words = (num_bytes >> 2) + ((num_bytes & 0x3) ? 1 : 0);
	idx = 0;
	for(i = 0; i < num_words; i++) {
		tmp_data = SFC_CMD_DATA;
		for(j = 0; j < 4; j++) {
			if(idx < num_bytes) {
				if(byte_order_be) {
					data[idx++] = (uint8_t)(tmp_data >> 24);
					tmp_data = tmp_data << 8;
				} else {
					data[idx++] = (uint8_t)tmp_data;
					tmp_data = tmp_data >> 8;
				}
			} else {
				break;
			}

		}
	}
	return SUCCESS;
}

void sfc_spi_wpn_actived()
{
	SFC_CTRL &= ~SFC_CTRL_SPI_WPN_Msk;
}
void sfc_spi_wpn_inactived()
{
	SFC_CTRL |= SFC_CTRL_SPI_WPN_Msk;
}
void sfc_spi_holdn_actived()
{
	SFC_CTRL &= ~SFC_CTRL_SPI_HOLDN_Msk;
}
void sfc_spi_holdn_inactived()
{
	SFC_CTRL |= SFC_CTRL_SPI_HOLDN_Msk;
}

